package com.sparrow.orm;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import com.sparrow.constant.*;
import com.sparrow.core.Cache;
import com.sparrow.core.Log;
import com.sparrow.core.asm.MethodAccessor;
import com.sparrow.enums.DIALECT;
import com.sparrow.enums.KEY_TYPE;
import com.sparrow.enums.ORM_ENTITY_META_DATA;
import com.sparrow.ioc.BeanFactory;
import com.sparrow.support.DaoSupport;
import com.sparrow.utils.Config;
import com.sparrow.utils.FileUtil;
import com.sparrow.utils.StringUtil;

public class JORMTemplate<T> implements DaoSupport<T> {
	/**
	 * 实体类
	 */
	private Class<?> clazz = null;
	/**
	 * 方法访问对象
	 */
	private MethodAccessor methodAccessor = null;
	/**
	 * 数据库辅助对象
	 */
	protected DBHelper dbhelper;
	/**
	 * 缓存单例对象
	 */
	private Cache cache = Cache.getInstance();
	private Dialect dialect;

	private String getDialect(String poolName) {
		Properties props = new Properties();
		String path = FileUtil.getInstance().getClassesPhysicPath();
		if (StringUtil.isNullOrEmpty(poolName)) {
			poolName = "dbpool";
		}
		try {
			props.load(new FileInputStream(path + "/" + poolName
					+ ".properties"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		String dialect = props.getProperty("dialect");
		if (!StringUtil.isNullOrEmpty(dialect)) {
			return dialect;
		} else {
			return DIALECT.MYSQL.toString().toLowerCase();
		}
	}

	/**
	 * JORM.java的构造函数
	 * 
	 * @author zhanglizhi
	 * @date 2012-4-7
	 * @version 1.0
	 * @param model
	 */
	public JORMTemplate() {
		this.clazz = (Class<?>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.dbhelper = DBHelper.getInstance();
		this.dialect = Dialect.getInstance(this.getDialect(null));
		this.methodAccessor = BeanFactory.getInstance().getProxyBean(
				this.clazz.getSimpleName());
		this.initMetaData();
	}

	public JORMTemplate(Enum<?> pn) {
		String poolName = pn.toString().toLowerCase();
		this.clazz = (Class<?>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.dbhelper = DBHelper.getInstance(pn);
		this.dialect = Dialect.getInstance(poolName);
		this.methodAccessor = BeanFactory.getInstance().getProxyBean(
				this.clazz.getSimpleName());
		this.initMetaData();
	}

	/**
	 * 初始化元数据
	 * 
	 * @author zhanglizhi
	 * @date 2012-4-8
	 * @version 1.0
	 */
	private void initMetaData() {
		// 当前实体类名
		String clazzName = this.clazz.getSimpleName();
		// 表名缓存key
		String keyTableName = clazzName + "."
				+ ORM_ENTITY_META_DATA.TABLE_NAME.ordinal();
		// SQL 方言
		String keyTableDialect = clazzName + "."
				+ ORM_ENTITY_META_DATA.DIALECT.ordinal();
		// hash打散的桶数
		String keyTableBucketCount = clazzName + "."
				+ ORM_ENTITY_META_DATA.TABLE_BUCKET_COUNT.ordinal();
		// 字段名
		String keyFields = clazzName + "."
				+ ORM_ENTITY_META_DATA.FIELDS.ordinal();
		// DB字段列表
		String keyDBFields = clazzName + "."
				+ ORM_ENTITY_META_DATA.DBFIELDS.ordinal();
		// 实体查询的where字段(key的组成：表名.类别索引.UniqueIndex)
		String keyEntityWhereField = clazzName + "."
				+ ORM_ENTITY_META_DATA.UNIQUE_FIELD.ordinal() + ".%1$s";
		// 实体查询的where类型(key的组成：表名.类别索引.UniqueIndex)
		String keyEntityWhereType = clazzName + "."
				+ ORM_ENTITY_META_DATA.UNIQUE_TYPE.ordinal() + ".%1$s";
		// SET方法用于反射注入实体对象
		String keySetMethods = clazzName + "."
				+ ORM_ENTITY_META_DATA.SET_METHODS.ordinal();
		// GET方法用于反射获取实体对象的字段值
		String keyGetMethods = clazzName + "."
				+ ORM_ENTITY_META_DATA.GET_METHODS.ordinal();
		// 插入记录SQL
		String keyInsertSQL = clazzName + "."
				+ ORM_ENTITY_META_DATA.SQL_INSERT.ordinal();
		// 更新记录SQL
		String keyUpdateSQL = clazzName + "."
				+ ORM_ENTITY_META_DATA.SQL_UPDATE.ordinal();
		// 删除记录SQL
		String keyDeleteSQL = clazzName + "."
				+ ORM_ENTITY_META_DATA.SQL_DELETE.ordinal();

		// 保存字段名列表
		String tableName = null;
		int bucketCount = 0;
		StringBuffer fields = new StringBuffer();
		List<DBField> dbFields = new ArrayList<DBField>();
		StringBuffer insertSQL = new StringBuffer("insert into ");
		StringBuffer insertParameter = new StringBuffer();
		StringBuffer updateSQL = new StringBuffer("update ");

		List<Method> setMethods = new ArrayList<Method>();
		List<Method> getMethods = new ArrayList<Method>();
		String primaryKeyFieldName = null;
		// 初始化表名
		if (this.clazz.isAnnotationPresent(Table.class)) {
			Table table = this.clazz.getAnnotation(Table.class);
			tableName = table.TableName();
			if (table.BucketCount() > 1) {
				bucketCount = table.BucketCount();
				this.cache.put(CACHE_KEY.ORM, keyTableBucketCount,
						table.BucketCount());
			}

			this.cache.put(CACHE_KEY.ORM, keyTableDialect, table.Dialect());
			this.cache.put(CACHE_KEY.ORM, keyTableName, tableName);
		}

		Method[] methods = this.clazz.getMethods();
		updateSQL.append(tableName);
		insertSQL.append(tableName);
		if (bucketCount > 0) {
			insertSQL.append("(bucketIndex)");
			updateSQL.append("(bucketIndex)");
		}
		insertSQL.append("(");
		updateSQL.append(" set ");
		for (int i = 0; i < methods.length; i++) {
			if (methods[i].isAnnotationPresent(DBField.class)) {
				if (methods[i].getName().startsWith("set")) {
					Log.getInstance().warm(
							"Annotation field must be above of getMethod");
				}
				DBField field = methods[i].getAnnotation(DBField.class);
				dbFields.add(field);
				getMethods.add(methods[i]);
				String fieldName = this.dialect.getOpenQuote()
						+ field.FieldName() + this.dialect.getCloseQuote();
				fields.append(fieldName);
				fields.append(",");
				try {
					setMethods.add(this.clazz.getMethod("set"
							+ methods[i].getName().substring(3), String.class));
				} catch (NoSuchMethodException e) {
					// 占位项为了与getMethods索引一致
					// 因为只有get 方法无对应在的set 方法
					setMethods.add(null);
					Log.getInstance().error(e,
							"jorm initMetaData() line num 147");
				}
				// insertSQL
				if (!field.KeyType().equals(KEY_TYPE.increment)) {
					insertSQL.append(fieldName);
					insertSQL.append(",");
					if (field.KeyType().equals(KEY_TYPE.sql)) {
						insertParameter.append("(sql),");
					} else {
						insertParameter.append("?,");
					}
				}

				// updateSQL
				if (field.IsKey()) {
					primaryKeyFieldName = this.dialect.getOpenQuote()
							+ field.FieldName() + this.dialect.getCloseQuote();
				} else if (field.Updateable()) {
					if (field.KeyType().equals(KEY_TYPE.sql)) {
						updateSQL.append(fieldName + "=(sql),");
					} else {
						updateSQL.append(fieldName + "=");
						updateSQL.append("?,");
					}
				}

				if (field.IsKey() || field.UniqueKeyIndex() > 0) {
					int uniqueKeyIndex = field.IsKey() ? 0 : field
							.UniqueKeyIndex();
					// 初始化查询条件类型
					this.cache.put(CACHE_KEY.ORM,
							String.format(keyEntityWhereType, uniqueKeyIndex),
							field.FieldType());
					// 初始化查询条件字段名
					this.cache.put(CACHE_KEY.ORM,
							String.format(keyEntityWhereField, uniqueKeyIndex),
							fieldName);
				}

			}
		}
		if (!StringUtil.isNullOrEmpty(fields)) {
			fields.deleteCharAt(fields.length() - 1);
		}
		insertSQL.deleteCharAt(insertSQL.length() - 1);
		insertParameter.deleteCharAt(insertParameter.length() - 1);
		insertSQL.append(")values(");
		insertSQL.append(insertParameter);
		insertSQL.append(")");

		updateSQL.deleteCharAt(updateSQL.length() - 1).append(
				" where " + primaryKeyFieldName + "=?");

		String deleteSQL = "delete from " + tableName + " where "
				+ primaryKeyFieldName + "=?";

		// 初始化insert SQL语句
		this.cache.put(CACHE_KEY.ORM, keyInsertSQL, insertSQL.toString());
		// 初始化delete SQL语句
		this.cache.put(CACHE_KEY.ORM, keyDeleteSQL, deleteSQL);
		// 初始化update SQL语句
		this.cache.put(CACHE_KEY.ORM, keyUpdateSQL, updateSQL.toString());
		// 初始化字段列表
		this.cache.put(CACHE_KEY.ORM, keyFields, fields.toString());
		// 初始化DB字段列表
		this.cache.put(CACHE_KEY.ORM, keyDBFields, dbFields);
		// 初始化set方法列表
		this.cache.put(CACHE_KEY.ORM, keySetMethods, setMethods);
		// 初始化get方法列表
		this.cache.put(CACHE_KEY.ORM, keyGetMethods, getMethods);
	}

	/**
	 * 获取元数据
	 * 
	 * @author zhanglizhi
	 * @date 2012-4-8
	 * @version 1.0
	 * @param ormEntityMetaData
	 * @param uniqueIndex
	 * @return
	 */
	private Object getMetaData(ORM_ENTITY_META_DATA ormEntityMetaData,
			int uniqueIndex) {
		// 当前实体类名
		String clazzName = this.clazz.getSimpleName();
		// 表名缓存key
		String cacheKey = clazzName + "." + ormEntityMetaData.ordinal();
		if ((ormEntityMetaData.ordinal() == ORM_ENTITY_META_DATA.UNIQUE_FIELD
				.ordinal())
				|| (ormEntityMetaData.ordinal() == ORM_ENTITY_META_DATA.UNIQUE_TYPE
						.ordinal())) {
			cacheKey += "." + uniqueIndex;
		}
		Object metaData = this.cache.get(CACHE_KEY.ORM, cacheKey);
		if (metaData == null) {
			Log.getInstance().warm("JORM getMetaData Metadata is NULL");
			return null;
		} else {
			return metaData;
		}
	}

	/**
	 * 获取元数据（重载)
	 * 
	 * @author zhanglizhi
	 * @date 2012-4-8
	 * @version 1.0
	 * @param ormEntityMetaData
	 * @return
	 */
	private Object getMetaData(ORM_ENTITY_META_DATA ormEntityMetaData) {
		return this.getMetaData(ormEntityMetaData,
				DB_CONFIG.ORM_PRIMARY_KEY_UNIQUE_INDEX);
	}

	private String getTableNameBySQLHelper(SQLHelper helper) {
		String tableName = this.getMetaData(ORM_ENTITY_META_DATA.TABLE_NAME)
				.toString();
		if (helper.getTableBucketKeyId() > -1) {
			tableName += helper.getTableBucketKeyId()
					% Integer
							.valueOf(this.getMetaData(
									ORM_ENTITY_META_DATA.TABLE_BUCKET_COUNT)
									.toString());
		}
		return tableName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#insert(T)
	 */
	@Override
	public int insert(T model) throws Exception {
		return this.insert(model, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#insert(T, java.sql.Connection)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public int insert(T model, Connection connection) throws Exception {
		String insertSQL = (String) this
				.getMetaData(ORM_ENTITY_META_DATA.SQL_INSERT);

		List<Method> getMethods = (List<Method>) this
				.getMetaData(ORM_ENTITY_META_DATA.GET_METHODS);

		List<DBField> dbFields = (List<DBField>) this
				.getMetaData(ORM_ENTITY_META_DATA.DBFIELDS);
		Method primaryKeySetMethod = null;
		boolean isIncrement = false;
		List<SQLParameter> parameters = new ArrayList<SQLParameter>();
		int tableIndex = -1;
		for (int i = 0; i < getMethods.size(); i++) {
			Object o = this.methodAccessor.get(model, getMethods.get(i)
					.getName());
			if (dbFields.get(i).IsKey()) {
				primaryKeySetMethod = this.clazz.getMethod(
						StringUtil.getSetBeanMethodName(getMethods.get(i)
								.getName().substring(3)), String.class);

			}

			if (dbFields.get(i).KeyType().equals(KEY_TYPE.hash)) {
				int tableBucketCount = Integer.valueOf(this.getMetaData(
						ORM_ENTITY_META_DATA.TABLE_BUCKET_COUNT).toString());
				int hashKey = Integer.valueOf(o.toString());
				if (hashKey == -1) {
					Log.getInstance().info("hashKey is -1 JORM LINE 313");
				}
				tableIndex = hashKey % tableBucketCount;
				parameters.add(new SQLParameter(dbFields.get(i).FieldType(),
						dbFields.get(i).FieldName(), o));
			}
			if (dbFields.get(i).KeyType().equals(KEY_TYPE.nokey)
					|| dbFields.get(i).KeyType().equals(KEY_TYPE.prepareuuid)) {
				parameters.add(new SQLParameter(dbFields.get(i).FieldType(),
						dbFields.get(i).FieldName(), o));
			} else if (dbFields.get(i).KeyType().equals(KEY_TYPE.uuid)) {
				String newUuid = Config.getNewUUID();
				parameters.add(new SQLParameter(dbFields.get(i).FieldType(),
						dbFields.get(i).FieldName(), newUuid));
				this.methodAccessor.set(model, primaryKeySetMethod.getName(),
						newUuid);
			} else if (dbFields.get(i).KeyType().equals(KEY_TYPE.sql)) {
				insertSQL = insertSQL.replace("(sql)", "(" + o + ")");
			} else if (dbFields.get(i).KeyType().equals(KEY_TYPE.increment)) {
				isIncrement = true;
			}

		}
		if (tableIndex > -1) {
			insertSQL = insertSQL.replace("(bucketIndex)",
					String.valueOf(tableIndex));
		}
		SQLParameter[] sqlParameters = new SQLParameter[parameters.size()];
		parameters.toArray(sqlParameters);
		if (isIncrement) {
			int id = this.dbhelper.executeAutoIncrementInsert(
					insertSQL.toString(), sqlParameters, connection);
			this.methodAccessor.set(model, primaryKeySetMethod.getName(),
					String.valueOf(id));
			return id;
		} else {
			this.dbhelper.executeUpdate(insertSQL.toString(), sqlParameters,
					connection);
			return 0;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#update(T)
	 */
	@Override
	public int update(T model) throws Exception {
		return this.update(model, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#update(T, java.sql.Connection)
	 */
	@Override
	public int update(T model, Connection connection) throws Exception {
		String updateSQL = (String) this
				.getMetaData(ORM_ENTITY_META_DATA.SQL_UPDATE);
		@SuppressWarnings("unchecked")
		List<Method> getMethods = (List<Method>) this
				.getMetaData(ORM_ENTITY_META_DATA.GET_METHODS);
		@SuppressWarnings("unchecked")
		List<DBField> dbFields = (List<DBField>) this
				.getMetaData(ORM_ENTITY_META_DATA.DBFIELDS);
		int tableIndex = -1;
		Set<SQLParameter> parameters = new LinkedHashSet<SQLParameter>();
		SQLParameter whereParameter = null;
		for (int i = 0; i < getMethods.size(); i++) {
			Object o = this.methodAccessor.get(model, getMethods.get(i)
					.getName());
			if (dbFields.get(i).KeyType().equals(KEY_TYPE.hash)) {
				int tableBucketCount = Integer.valueOf(this.getMetaData(
						ORM_ENTITY_META_DATA.TABLE_BUCKET_COUNT).toString());
				tableIndex = Integer.valueOf(o.toString()) % tableBucketCount;
				whereParameter = new SQLParameter(dbFields.get(i).FieldType(),
						dbFields.get(i).FieldName(), o);
			}
			if (dbFields.get(i).IsKey()) {
				whereParameter = new SQLParameter(dbFields.get(i).FieldType(),
						dbFields.get(i).FieldName(), o);
			} else if (dbFields.get(i).Updateable()) {
				if (dbFields.get(i).KeyType().equals(KEY_TYPE.sql)) {
					updateSQL = updateSQL.replace("(sql)", "(" + o + ")");
				} else {
					parameters.add(new SQLParameter(
							dbFields.get(i).FieldType(), dbFields.get(i)
									.FieldName(), o));
				}
			}
		}
		if (tableIndex > -1) {
			updateSQL = updateSQL.replace("(bucketIndex)",
					String.valueOf(tableIndex));
		}
		parameters.add(whereParameter);
		SQLParameter[] sqlParameters = new SQLParameter[parameters.size()];
		parameters.toArray(sqlParameters);
		return this.dbhelper
				.executeUpdate(updateSQL, sqlParameters, connection);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#update(com.sparrow.orm.SQLHelper)
	 */
	@Override
	public int update(SQLHelper helper) throws Exception {
		return this.update(helper, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#update(com.sparrow.orm.SQLHelper,
	 * java.sql.Connection)
	 */
	@Override
	public int update(SQLHelper helper, Connection connection) throws Exception {
		String update = String.format("update %1$s set %2$s where %3$s",
				this.getTableNameBySQLHelper(helper), helper.getSetClause(),
				helper.getWhereClause());
		SQLParameter[] parameters = helper.getParameters();
		System.out.println(update);
		if (parameters == null || parameters.length == 0) {
			return this.dbhelper.executeUpdate(update, connection);
		} else {
			return this.dbhelper.executeUpdate(update, parameters, connection);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#delete(java.lang.Object)
	 */
	@Override
	public int delete(Object id) throws Exception {
		return this.delete(id, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#delete(java.lang.Object,
	 * java.sql.Connection)
	 */
	@Override
	public int delete(Object id, Connection connection) throws Exception {
		String deleteSql = (String) this
				.getMetaData(ORM_ENTITY_META_DATA.SQL_DELETE);
		Class<?> idType = (Class<?>) this
				.getMetaData(ORM_ENTITY_META_DATA.UNIQUE_TYPE);
		String uniqueField = this
				.getMetaData(ORM_ENTITY_META_DATA.UNIQUE_FIELD).toString();
		SQLParameter[] sqlParameters = new SQLParameter[] { new SQLParameter(
				idType, uniqueField, id) };
		return this.dbhelper
				.executeUpdate(deleteSql, sqlParameters, connection);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#delete(com.sparrow.orm.SQLHelper)
	 */
	@Override
	public int delete(SQLHelper helper) throws Exception {
		return this.delete(helper, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#delete(com.sparrow.orm.SQLHelper,
	 * java.sql.Connection)
	 */
	@Override
	public int delete(SQLHelper helper, Connection connection) throws Exception {
		String delete = String.format("DELETE FROM %1$s WHERE %2$s",
				this.getTableNameBySQLHelper(helper), helper.getWhereClause());
		SQLParameter[] parameters = helper.getParameters();
		if (parameters == null || parameters.length == 0) {
			return this.dbhelper.executeUpdate(delete, connection);
		} else {
			return this.dbhelper.executeUpdate(delete, parameters, connection);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#select(com.sparrow.orm.SQLHelper)
	 */
	@Override
	public ResultSet select(SQLHelper helper) {
		if (helper == null)
			helper = new SQLHelper();
		helper.setRecordCount(this.getCount(helper));
		if (helper.getRecordCount() == 0) {
			return null;
		} else {
			StringBuffer selectSql = new StringBuffer("select ");
			String fields = helper.getFields();
			String whereClause = helper.getWhereClause();
			String orderClause = helper.getOrderClause();
			if (StringUtil.isNullOrEmpty(fields)) {
				selectSql.append(this.getMetaData(ORM_ENTITY_META_DATA.FIELDS));
			} else {
				selectSql.append(fields);
			}
			selectSql.append(" from " + this.getTableNameBySQLHelper(helper)
					+ " as " + this.clazz.getSimpleName().toLowerCase());
			if (!StringUtil.isNullOrEmpty(whereClause)) {
				selectSql.append(" where " + whereClause);
			}

			if (!StringUtil.isNullOrEmpty(orderClause)) {
				selectSql.append(" order by " + orderClause);
			}

			if (!StringUtil.isNullOrEmpty(helper.getPageSize())
					&& helper.getPageSize() != COMMON.ALL) {
				selectSql.append(helper.getLimitClause());
			}
			return this.dbhelper.executeQuery(selectSql.toString(),
					helper.getParameters());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getEntity(java.lang.Object)
	 */
	@Override
	public T getEntity(Object id) throws Exception {
		return this.getEntity(id, 0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getEntity(java.lang.Object, int)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T getEntity(Object key, int uniqueKeyIndex) throws Exception {
		System.out.println("getEntity(Object key, int uniqueKeyIndex)" + key
				+ "|" + uniqueKeyIndex);
		T model = null;
		List<Method> setMethods = (List<Method>) this
				.getMetaData(ORM_ENTITY_META_DATA.SET_METHODS);

		List<DBField> dbFields = (List<DBField>) this
				.getMetaData(ORM_ENTITY_META_DATA.DBFIELDS);

		String uniqueField = this.getMetaData(
				ORM_ENTITY_META_DATA.UNIQUE_FIELD, uniqueKeyIndex).toString();

		StringBuffer select = new StringBuffer("select ");
		select.append(this.getMetaData(ORM_ENTITY_META_DATA.FIELDS));
		select.append(" from "
				+ this.getMetaData(ORM_ENTITY_META_DATA.TABLE_NAME));
		select.append(" where " + uniqueField + "=?");

		Class<?> uniqueType = (Class<?>) this.getMetaData(
				ORM_ENTITY_META_DATA.UNIQUE_TYPE, uniqueKeyIndex);

		SQLParameter[] parameters = new SQLParameter[] { new SQLParameter(
				uniqueType, uniqueField, key) };

		ResultSet rs = null;
		try {
			rs = this.dbhelper.executeQuery(select.toString(), parameters);
			if (rs.next()) {
				model = (T) this.clazz.getConstructor().newInstance();
				Iterator<Method> it = setMethods.iterator();
				Method setMethod = null;
				for (int i = 0; i < setMethods.size(); i++) {
					setMethod = it.next();
					if (setMethod != null) {
						try {
							this.methodAccessor.set(model, setMethod.getName(),
									rs.getString(dbFields.get(i).FieldName()));
						} catch (Exception e) {
							Log.getInstance().error(e, select.toString());
						}
					}
				}
			}
		} finally {
			if (rs != null) {
				this.dbhelper.release(rs);
			}
		}
		return model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getEntity(com.sparrow.orm.SQLHelper)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T getEntity(SQLHelper helper) throws Exception {
		T model = null;
		String whereClause = helper.getWhereClause();
		String orderClause = helper.getOrderClause();
		List<Method> setMethods = (List<Method>) this
				.getMetaData(ORM_ENTITY_META_DATA.SET_METHODS);

		List<DBField> dbFields = (List<DBField>) this
				.getMetaData(ORM_ENTITY_META_DATA.DBFIELDS);

		StringBuffer selectSQL = new StringBuffer("select ");
		selectSQL.append(this.getMetaData(ORM_ENTITY_META_DATA.FIELDS));
		selectSQL.append(" from " + this.getTableNameBySQLHelper(helper)
				+ " as " + this.clazz.getSimpleName().toLowerCase());
		if (!StringUtil.isNullOrEmpty(whereClause)) {
			selectSQL.append(" where " + whereClause);
		}
		if (!StringUtil.isNullOrEmpty(orderClause)) {
			selectSQL.append(" order by " + orderClause);
		}
		selectSQL.append(helper.getLimitClause());
		ResultSet rs = null;
		try {
			rs = this.dbhelper.executeQuery(selectSQL.toString());
			if (rs.next()) {
				model = (T) this.clazz.getConstructor().newInstance();
				for (int i = 0; i < setMethods.size(); i++) {
					if (setMethods.get(i) != null) {
						try {
							this.methodAccessor.set(model, setMethods.get(i)
									.getName(), rs.getString(dbFields.get(i)
									.FieldName()));
						} catch (Exception e) {
							Log.getInstance().error(e);
						}
					}
				}
			}
		} finally {
			this.dbhelper.release(rs);
		}
		return model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getList(com.sparrow.orm.SQLHelper)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> getList(SQLHelper helper) throws Exception {
		List<T> list = new ArrayList<T>();
		List<Method> setMethods = (List<Method>) this
				.getMetaData(ORM_ENTITY_META_DATA.SET_METHODS);
		List<DBField> dbfields = (List<DBField>) this
				.getMetaData(ORM_ENTITY_META_DATA.DBFIELDS);
		ResultSet rs = this.select(helper);
		if (rs != null) {
			while (rs.next()) {
				T m = (T) this.clazz.getConstructor().newInstance();
				for (int i = 0; i < setMethods.size(); i++) {
					if (setMethods.get(i) != null) {
						this.methodAccessor.set(m, setMethods.get(i).getName(),
								rs.getString(dbfields.get(i).FieldName()));
					}
				}
				list.add(m);
			}
			this.dbhelper.release(rs);
		}
		return list;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getCount(java.lang.Object, int)
	 */
	@Override
	public int getCount(Object key, int uniqueKeyIndex) throws Exception {
		StringBuffer select = new StringBuffer("select count(*) from "
				+ this.getMetaData(ORM_ENTITY_META_DATA.TABLE_NAME));
		select.append(" where "
				+ this.getMetaData(ORM_ENTITY_META_DATA.UNIQUE_FIELD,
						uniqueKeyIndex) + "=?");

		Class<?> uniqueKeyType = (Class<?>) this.getMetaData(
				ORM_ENTITY_META_DATA.UNIQUE_TYPE, uniqueKeyIndex);

		String uniqueField = this.getMetaData(
				ORM_ENTITY_META_DATA.UNIQUE_FIELD, uniqueKeyIndex).toString();

		SQLParameter[] parameters = new SQLParameter[] { new SQLParameter(
				uniqueKeyType, uniqueField, key) };

		Object count = this.dbhelper.executeScalar(select.toString(),
				parameters);
		if (count == null) {
			return 0;
		} else {
			return Integer.valueOf(count.toString());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getCount(java.lang.Object)
	 */
	@Override
	public int getCount(Object key) throws Exception {
		return this.getCount(key, DB_CONFIG.ORM_PRIMARY_KEY_UNIQUE_INDEX);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getCount(com.sparrow.orm.SQLHelper)
	 */
	@Override
	public int getCount(SQLHelper helper) {
		String field = helper.getFields();
		String whereClause = helper.getWhereClause();

		if (StringUtil.isNullOrEmpty(field) || field.contains(",")) {
			field = "*";
		}
		if (helper.isDistinct()) {
			field = "distinct " + field;
		}
		String select = String.format("select count(%1$s) from %2$s %3$s",
				field, this.getTableNameBySQLHelper(helper) + " as "
						+ this.clazz.getSimpleName().toLowerCase(),
				StringUtil.isNullOrEmpty(whereClause) ? "" : " where "
						+ whereClause);
		Object count = this.dbhelper.executeScalar(select,
				helper.getParameters());
		if (count == null) {
			return 0;
		} else {
			return Integer.valueOf(count.toString());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getAggregate(java.lang.String)
	 */
	@Override
	public int getAggregate(String aggregate) throws Exception {
		String value = this.getFieldValue(aggregate, null, COMMON.ALL);
		if (StringUtil.isNullOrEmpty(value)) {
			return 0;
		} else {
			return Integer.valueOf(value);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getFieldValue(java.lang.String,
	 * java.lang.String)
	 */
	@Override
	public String getFieldValue(String fieldName, String value)
			throws Exception {
		return this.getFieldValue(fieldName, value,
				DB_CONFIG.ORM_PRIMARY_KEY_UNIQUE_INDEX);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sparrow.orm.DaoSupport#getFieldValue(java.lang.String,
	 * java.lang.Object, int)
	 */
	@Override
	public String getFieldValue(String fieldName, Object key, int uniqueIndex)
			throws Exception {

		String select = String.format("select %1$s from %2$s", fieldName,
				this.getMetaData(ORM_ENTITY_META_DATA.TABLE_NAME) + " as "
						+ this.clazz.getSimpleName().toLowerCase());
		Object fieldValue = null;
		if (uniqueIndex >= 0) {
			String uniqueFieldName = this.getMetaData(
					ORM_ENTITY_META_DATA.UNIQUE_FIELD, uniqueIndex).toString();
			select += String.format(" where %1$s=?", uniqueFieldName);

			Class<?> uniqueType = (Class<?>) this.getMetaData(
					ORM_ENTITY_META_DATA.UNIQUE_TYPE, uniqueIndex);
			String uniqueField = this.getMetaData(
					ORM_ENTITY_META_DATA.UNIQUE_FIELD, uniqueIndex).toString();

			SQLParameter[] parameters = new SQLParameter[] { new SQLParameter(
					uniqueType, uniqueField, key) };
			fieldValue = this.dbhelper.executeScalar(select, parameters);
		} else {
			fieldValue = this.dbhelper.executeScalar(select);
		}

		if (fieldValue == null) {
			return null;
		} else {
			return String.valueOf(fieldValue);
		}
	}

	@Override
	public void release(ResultSet rs) {
		this.dbhelper.release(rs);
	}
}
